package com.excel;

import com.excel.annotations.XlsCell;
import com.excel.build.Excel;
import com.excel.build.impl.TableToExcel;
import com.excel.entity.CCell;
import com.excel.entity.XlsCellCellType;
import com.excel.read.ExcelCallBack;
import com.excel.read.ExcelUtils;
import com.excel.write.CHead;
import com.excel.write.CRow;
import com.excel.write.ExcelContent;
import com.excel.write.base.impl.ExcelWrite;
import com.excel.write.base.impl.ExcelWriteFile;
import com.excel.write.base.impl.ExcelWriteOutputStream;
import com.sqlsession.database.CTable;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.poi.ss.usermodel.CellType;

import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.*;

public class ExcelGenerator {


    //通用的
    public static void TablesWriteToFile(String cacheDir, String fileName, List<CTable> tables) {
        Excel excel = new TableToExcel(tables);
        ExcelWrite.write(cacheDir, fileName, excel);
    }

    //通用的
    public static void writeToFile(String cacheDir, String fileName, Excel excel) {
        ExcelWrite.write(cacheDir, fileName, excel);
    }

    //数据类表格保存到文件
    public static void writeToFile(String cacheDir, String fileName, List<?> classz) {
        List<ExcelContent> excelContent = createExcelContent(classz);
        ExcelWriteFile.write(cacheDir, fileName, excelContent);
    }

    //数据库转化成Excel 下载
    public static void writeToOutPutStream(OutputStream outputStream, List<?> classz) {
        List<ExcelContent> excelContent = createExcelContent(classz);
        ExcelWriteOutputStream excelWriteOutputStream = new ExcelWriteOutputStream(outputStream);
        excelWriteOutputStream.write(excelContent);
    }

    //读取Excel
    public static <T> ExcelUtils<T> read(String path, ExcelCallBack<T> excelCallBack) {
        ExcelUtils<T> excelUtils = ExcelUtils.read(path, excelCallBack);
        return excelUtils;
    }

    private static void process(Map<String, XlsCellCellType> map, Class<?> classz) {
        if (classz.isAssignableFrom(Object.class)) {
            return;
        }
        Field[] declaredFields = classz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            XlsCell xlsCell = declaredField.getAnnotation(XlsCell.class);
            String value = Optional.ofNullable(xlsCell).map(XlsCell::value).orElse(declaredField.getName());
            CellType cellType = xlsCell.cellType();
            XlsCellCellType xlsCellCellType = new XlsCellCellType(value, cellType);
            xlsCellCellType.setaClass(classz);
            map.put(declaredField.getName(), xlsCellCellType);
        }
    }

    private static List<ExcelContent> createExcelContent(List<?> classz) {
        List<ExcelContent> excelContents = new LinkedList<>();
        if (ObjectUtils.isEmpty(classz)) {
            return excelContents;
        }
        Map<String, XlsCellCellType> headeres = new LinkedHashMap<>();
        Object o = classz.get(0);
        Class<?> aClass = o.getClass();
        while (!aClass.isAssignableFrom(Object.class)) {
            process(headeres, aClass);
            aClass = aClass.getSuperclass();
        }
        CHead.CHeadBuilder cHeadBuilder = CHead.CHeadBuilder.aCHead();
        for (Map.Entry<String, XlsCellCellType> entry : headeres.entrySet()) {
            XlsCellCellType cellType = entry.getValue();
            cHeadBuilder.add(CCell.CCellBuilder.aCCell().withCellType(cellType.getCellType()).withValue(cellType.getName()).build());
        }
        ExcelContent.ExcelContentBuilder excelContentBuilder = ExcelContent.ExcelContentBuilder.anExcelContent()
                .withName("sheet1")
                .withCHead(cHeadBuilder.build());
        for (Object object : classz) {
            CRow.CRowBuilder cRowBuilder = CRow.CRowBuilder.aCRow();
            for (Map.Entry<String, XlsCellCellType> entry : headeres.entrySet()) {
                XlsCellCellType value = entry.getValue();
                createCRow(cRowBuilder, value, entry.getKey(), object);
            }
            excelContentBuilder.withCRow(cRowBuilder.build());
        }
        excelContents.add(excelContentBuilder.build());
        return excelContents;
    }

    private static void createCRow(CRow.CRowBuilder cRowBuilder, XlsCellCellType xlsCellCellType, String fileName, Object object) {
        try {
            CellType cellType = xlsCellCellType.getCellType();
            Class<?> aClass = xlsCellCellType.getaClass();
            Field field = aClass.getDeclaredField(fileName);
            field.setAccessible(true);
            Object value = field.get(object);
            cRowBuilder.withCell(CCell.CCellBuilder.aCCell().withCellType(cellType).withValue(String.valueOf(value)).build());
            field.setAccessible(false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
